<?php
/**
 * This file is part of the Yacms (http://www.yacms.org)
 * Copyright (c) 2019 gylr0505 (http://www.yacms.org)
 *
 * Author: 鬼一浪人 <gylr0505@163.com>
 *
 * DateTime: 19-10-25 下午10:00
 * Description:
 */
 
declare(strict_types = 1);

namespace App\Template\Queue;

use App\Template\TemplateInterface;
use Carbon\Carbon;
use Swoft\Redis\Redis;

class ProducerIntervalControl
{
    const DEFAULT_INTERVAL_FREQUENCY = 300;

    const ALL_DAY_SECONDS = 86400;
    /**
     * 缓存中记录频次的key
     */
    const CURRENT_INTERVAL_FREQUENCY_KEY = 'current_interval_frequency';

    private $intervalFrequency = self::DEFAULT_INTERVAL_FREQUENCY;

    private $cycles = self::ALL_DAY_SECONDS;

    /**
     * @var TemplateInterface
     */
    private $template;

    /**
     * ProducerIntervalControl constructor.
     * @param TemplateInterface $template
     * @param array $params
     */
    public function __construct(TemplateInterface $template, $params = [])
    {
        $this->template = $template;
        $this->parseParams($params);
        $this->initHash();
    }

    /**
     * @param array $params
     */
    private function parseParams($params = [])
    {
        $this->intervalFrequency = $params['intervalFrequency'] ?? self::DEFAULT_INTERVAL_FREQUENCY;
        $this->cycles = $params['cycles'] ?? self::ALL_DAY_SECONDS;
    }

    /**
     *
     */
    private function initHash()
    {
        $exists = Redis::exists($this->generatorCacheKey());

        if ($exists){
            return;
        }

        $now = Carbon::now(new \DateTimeZone('PRC'));
        $cache = [
            'begin_datetime' => (string)$now,
            'end_datetime'   => (string)$now->addSeconds($this->cycles)
        ];

        Redis::hMSet($this->generatorCacheKey(),$cache);
        Redis::expire($this->generatorCacheKey(),$this->cycles);
    }

    /**
     * @return bool
     */
    public function isNext()
    {

        if (!$this->cycles){
            return false;
        }

        if (!Redis::exists($this->generatorCacheKey())){
            return false;
        }

        $hashAll = Redis::hGetAll($this->generatorCacheKey());

        $current = $this->generatorCurrentFrequency($hashAll['begin_datetime'] ?? '');

        if ($current > $this->generatorMaxFrequency()){
            return false;
        }

        $last = (int)Redis::hGet($this->generatorCacheKey(),self::CURRENT_INTERVAL_FREQUENCY_KEY);
        //$last为0表示第一次
        if ($last < $current || $last == 0){
            //次数加1
            Redis::hIncrBy($this->generatorCacheKey(),self::CURRENT_INTERVAL_FREQUENCY_KEY,1);
            return true;
        }

        return false;
    }

    /**
     * @param string $begin_datetime
     * @return float
     */
    public function generatorCurrentFrequency($begin_datetime = '')
    {
        $timezone = new \DateTimeZone('PRC');
        $now = Carbon::now($timezone);
        $interval = $now->diffInSeconds($begin_datetime ?: Carbon::today($timezone));
        return ceil($interval / $this->intervalFrequency);
    }

    /**
     * @return float|int
     */
    public function generatorMaxFrequency()
    {
        if (!$this->intervalFrequency){
            return 1;
        }
        return ceil($this->cycles / $this->intervalFrequency);
    }

    /**
     * 当前时间周期的hash顶级key
     * @return string
     */
    protected function generatorCacheKey()
    {
        return 'interval_control_hash_keys:'.$this->template->getType().':'.$this->template->getId();
    }
}